<?php
/**
 * Created by PhpStorm.
 * User: Keter
 * Date: 2016/7/28
 * Time: 20:25
 */
class CreateRoom extends ApiRedisBase
{
    protected $serverID;
    protected $roomDiamonds;
    public $roomRedis;

    public function logic()
    {
        $userInfo = $this->checkUser(true);
        $userQuery = new UserQuery();
        $this->roomRedis = $this->redis('room_status');

        $roomInfo  = $userQuery->queryRoomInfo($this->uid, $this->platform);
        $this->i('create_room_query', ['roomInfo' => $roomInfo]);

        if (empty($roomInfo)) {
            $this->roomDiamonds = new RoomDiamonds();
            $this->params = $this->formatNumber($this->params);

            //计算需扣除的房卡总数
            $totalDiamonds = $this->roomDiamonds->calcTotalDiamonds(
                $this->params['gameType'], $this->params['totalRound']
            );

            //检测用户房卡是否足够
            $this->i('totalDiamonds', $totalDiamonds);
            $this->i('userInfo', $userInfo);
            $this->roomDiamonds->checkDiamond($userInfo, $totalDiamonds);

            //计算需扣除的免费和付费房卡
            $diamonds = $this->roomDiamonds->calcDiamond($userInfo, $totalDiamonds);

            //创建房间，记录房间的房卡消耗
            $roomInfo = $this->createNewRoom($diamonds);
        } else {
            unset($roomInfo['serverID']); //与创建时保存一致的返回结果
        }

        $this->returnData('suc_create_room', $roomInfo);
    }

    /**
     * 创建房间
     * @return array
     */
    public function createNewRoom($diamonds)
    {
        $roomID = $this->geneRoomID($diamonds);
        if (!$roomID) {
            $this->returnError('failed_create_room');
        }

        $roomID = (integer)$roomID;
        $roomInfo = $this->applyRoom($roomID);
        if (!$roomInfo) {
            $this->i('app_mode1', _APP_MODE);
            $this->e('failed_apply_room', $roomInfo);
            $this->returnError('failed_apply_room', -1, $roomInfo);
        }

        $result = $this->redis('room_status')->hMset('UR:' . $this->uid, ['roomID' => $roomID]);
        if (!$result) {
            $this->i('app_mode1', _APP_MODE);
            $this->e('failed_save_user_room', $result);
            $this->returnError('failed_save_user_room', -1, ['roomID' => $roomID]);
        }

        $data = array(
            'roomID'      => $roomID,
            'serverIP'    => $roomInfo['serverIP'],
            'serverPort'  => (integer)$roomInfo['serverPort'],
        );

        return $data;
    }

    /**
     * 生成房间ID
     * @param $diamonds
     * @return int|string
     */
    public function geneRoomID($diamonds)
    {
        $roomID = 0;
        for ($i = 0; $i < 20; $i++) {
            $randID= mt_rand(1, 9) . sprintf('%05d', mt_rand(1, 99999));
            if (!$this->roomRedis->exists("R:" . $randID)) {
                $roomID = $randID;
                break;
            }
        }

        if ($roomID) {
            $roomInfo = array(
                'roomID'      => $roomID,
                'serverID'    => 0,
                'realRound'   => 0,
                'gameType'    => $this->params['gameType'],
                'totalRound'  => $this->params['totalRound'],
                'huType'      => $this->params['huType'],
                'playConfig'  => json_encode($this->params['playConfig']),
                'birdCount'   => $this->params['birdCount'],
                'freeDiamond' => $diamonds['freeDiamond'],
                'paidDiamond' => $diamonds['paidDiamond'],
                'creator'     => $this->uid,
                'createTime'  => time()
            );
            $result = $this->roomRedis->hMset('R:' . $roomID, $roomInfo);
            if (!$result) {
                $this->returnError('failed_save_room');
            }
        }

        return $roomID;
    }

    /**
     * 申请房间
     * @param $roomID
     * @return array|mixed|string
     */
    public function applyRoom($roomID)
    {
        //生成要提交的参数
        $data = array(
            'key' => GameConfig::$room_config['create_key'],
            'cmd' => 'createRoom',
            'msg' => array(
                'roomID' => $roomID,
                'config' => array(
                    "mahjongType"  => $this->params['gameType'],
                    "juShu"        => $this->params['totalRound'],
                    "huPaiLeiXing" => $this->params['huType'],
                    "keXuan"       => $this->params['playConfig'],
                    "niao"         => $this->params['birdCount'],
                    "IPLimit"      => (integer)$this->params['ipLimit']
                ),
                'uid' => $this->uid
            ),
        );

        $data = $this->formatNumber($data);

        //如果失败，重新换一个服务器，三次机会
        for ($i = 0; $i < 3; $i ++) {
            try {
                //选择服务器
                $serverInfo = $this->selectOneServer();
                $this->i('apply_room', ['data'=> $data, 'serverInfo'=> $serverInfo]);
                //申请一个房间
                $result = $this->applyOneRoom($serverInfo, $data);
            } catch (Exception $e) {
                continue;
            }
            if ($result['code'] == 0) {
                break;
            } elseif ($result['code'] == 1) {
                if ($serverInfo['type'] != GameServer::$serverSpecial) {
                    continue;
                }
            }
        }

        $this->i('apply_room_result', $result);

        //创建成功，返回数据
        if ($result && isset($result['code']) && $result['code'] == 0) {
            //IOS需要域名
            if ($this->platform == GlobalConfig::PLATFORM_IOS) {
                $result['serverIP'] = $serverInfo['domain'];
            } else {
                $result['serverIP'] = $serverInfo['ip'];
            }
            $result['serverPort'] = $serverInfo['serverPort'];
            $this->i('updateRoomServer', $serverInfo);
            try {
                $this->updateRoomServer($roomID, $serverInfo['serverID']);
            } catch (Exception $e) {
                $this->destoryRoom($roomID);
            }
            return $result;
        } else {
            //创建失败，删除房间
            $this->destoryRoom($roomID);
            if (isset($result['code'])) {
                if ($result['code'] == 1) {
                    $this->returnError('over_room_num');
                }
            }
            return array();
        }
    }

    /**
     * 更新房间的服务器ID
     * @param $roomID
     * @param $serverID
     */
    public function updateRoomServer($roomID, $serverID)
    {
        $result = $this->roomRedis->hMset('R:' . $roomID, ['serverID' => $serverID]);
        if (!$result) {
            $this->e('no_server');
            return $this->throwError('failed_save_room');
        }
    }

    /**
     * 选择一台服务器
     * @param $gameServer
     * @return mixed
     */
    public function selectOneServer()
    {
        //选择服务器
        $gameServer = new GameServer();

        if (_APP_MODE === 'product') {
            /**
             * 生产环境
             */
            $serverID = $gameServer->selectServer($this->channelId);
        } else {
            /**
             * 测试环境
             */
            $serverID = $gameServer->getTestServer($this->uid); //测试人员专用服务器
            if (empty($serverID)) {
                $serverID = $gameServer->selectServer($this->channelId);
            }
        }

        if (!$gameServer->existsServer($serverID)) {
            $this->e('no_server');
            return $this->throwError('no_server');
        }

        //获取服务器的地址信息
        $serverInfo= $gameServer->getServerAddress($serverID);
        if (!$serverInfo) {
            $this->e('no_server_info');
            return $this->throwError('no_server_info');
        }

        $serverInfo['serverID'] = $serverID;
        return $serverInfo;
    }

    /**
     * 请求创建房间
     * @param $SocketRequest
     * @param $serverInfo
     * @param $data
     * @return mixed
     */
    public function applyOneRoom($serverInfo, $data)
    {
        try {
            $socketRequest = new SocketRequest();
            $ip = $serverInfo['lanIP'] ? $serverInfo['lanIP'] : $serverInfo['ip'];
            $requestResult = $socketRequest->request(
                $ip,
                $serverInfo['agentPort'],
                $data,
                1
            );
        } catch (Exception $e) {
            $this->i('app_mode2', _APP_MODE);
            $this->e('failed_apply_room');
            return $this->throwError('failed_apply_room');
        }

        $result = json_decode($requestResult, true);
        if (empty($result)) {
            $this->i('app_mode3', _APP_MODE);
            $this->i('apply_room_result', ['result'=>$requestResult]);
            return $this->throwError('failed_apply_room');
        }

        return $result;
    }

    /**
     * 销除房间
     * @param $roomID
     */
    public function destoryRoom($roomID)
    {
        $this->roomRedis->del("R:" . $roomID);
    }
}